﻿using System;
using System.Diagnostics;
using System.IO;
using System.Text;
using System.Threading.Tasks;

namespace GameTools.Services.ScriptExecutionService
{
    public enum ScriptMode
    {
        Observe,    // 无窗口 + 捕获输出
        Debug,      // 弹出控制台窗口
        Silent      // 无窗口 + 不捕获输出
    }

    public class ScriptExecutionService
    {
        static ScriptExecutionService()
        {
            Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
        }

        /// <summary>
        /// 执行脚本（支持 .bat 和 .py）
        /// </summary>
        /// <param name="filePath">脚本路径</param>
        /// <param name="arguments">参数</param>
        /// <param name="mode">执行模式（观察 / 调试 / 静默）</param>
        /// <param name="logCallback">实时日志回调（可选）</param>
        public async Task<(bool success, string output)> ExecuteScriptAsync(
            string filePath,
            string arguments = "",
            ScriptMode mode = ScriptMode.Observe,
            Action<string>? logCallback = null)
        {
            if (!File.Exists(filePath))
                return (false, $"❌ 文件不存在: {filePath}");

            string ext = Path.GetExtension(filePath).ToLower();
            string shell, args;
            Encoding encoding;

            if (ext == ".bat")
            {
                shell = "cmd.exe";
                args = $"/c \"{filePath}\" {arguments}";
                encoding = Encoding.GetEncoding("GB2312");
            }
            else if (ext == ".py")
            {
                shell = "python";
                args = $"\"{filePath}\" {arguments}";
                encoding = Encoding.UTF8;
            }
            else
            {
                return (false, $"❌ 不支持的脚本类型: {ext}");
            }

            string workingDirectory = Path.GetDirectoryName(filePath) ?? Environment.CurrentDirectory;

            var startInfo = new ProcessStartInfo
            {
                FileName = shell,
                Arguments = args,
                WorkingDirectory = workingDirectory,
                UseShellExecute = mode != ScriptMode.Observe,
                CreateNoWindow = mode != ScriptMode.Debug,
            };

            if (mode == ScriptMode.Observe)
            {
                startInfo.RedirectStandardOutput = true;
                startInfo.RedirectStandardError = true;
                startInfo.StandardOutputEncoding = encoding;
                startInfo.StandardErrorEncoding = encoding;

            }

            try
            {
                using var process = new Process { StartInfo = startInfo };

                if (mode == ScriptMode.Observe)
                {
                    var outputBuilder = new StringBuilder();
                    var errorBuilder = new StringBuilder();

                    process.OutputDataReceived += (s, e) =>
                    {
                        if (e.Data != null)
                        {
                            outputBuilder.AppendLine(e.Data);
                            logCallback?.Invoke(e.Data); // 实时输出到回调
                        }
                    };
                    process.ErrorDataReceived += (s, e) =>
                    {
                        if (e.Data != null)
                        {
                            errorBuilder.AppendLine(e.Data);
                            logCallback?.Invoke(e.Data); // 实时输出到回调
                        }
                    };

                    process.Start();
                    process.BeginOutputReadLine();
                    process.BeginErrorReadLine();

                    await process.WaitForExitAsync();

                    string output = outputBuilder.ToString().Trim();
                    string error = errorBuilder.ToString().Trim();

                    return process.ExitCode == 0
                        ? (true, output)
                        : (false, $"{output}{Environment.NewLine}{error}".Trim());
                }
                else
                {
                    process.Start();
                    await process.WaitForExitAsync();

                    return (process.ExitCode == 0, $"已执行，退出码: {process.ExitCode}");
                }
            }
            catch (Exception ex)
            {
                return (false, $"❌ 执行异常: {ex.Message}");
            }
        }
    }
}